﻿using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Common.Wechat
{
    internal static class HttpHelper
    {
        private static readonly ConcurrentDictionary<string, HttpClient> pool = new System.Collections.Concurrent.ConcurrentDictionary<string, HttpClient>();
        private static Uri GetBaseAddress(Uri targetUri)
        {
            string baseAddress = $"{targetUri.Scheme}://{targetUri.Host}";
            if (targetUri.Port != 80 && targetUri.Port != 443)
            {
                baseAddress += "/" + targetUri.Port;
            }
            return new Uri(baseAddress);
        }
        private static HttpClient GetHttpClient(Uri targetUri)
        {
            var baseAddress = GetBaseAddress(targetUri);
            return pool.GetOrAdd(baseAddress.ToString(), _ =>
            {
                var hc = new HttpClient();
                hc.BaseAddress = baseAddress;
                return hc;
            });
        }
        private static bool IsSuccess(HttpStatusCode statusCode)
        {
            return statusCode == HttpStatusCode.OK || statusCode == HttpStatusCode.NoContent || statusCode == HttpStatusCode.Created || statusCode == HttpStatusCode.Accepted;
        }
        public static async Task<string> GetAsync(string url, string query, int timeout)
        {
            var targetUri = new Uri(url);
            var client = GetHttpClient(targetUri);
            if (!string.IsNullOrEmpty(query))
            {
                string concatChar = url.Contains("?") ? "&" : "?";
                url += concatChar + query;
            }
            client.Timeout = TimeSpan.FromSeconds(timeout);
            var resp = await client.GetAsync(url);
            if (!IsSuccess(resp.StatusCode))
            {
                return null;
            }
            return await resp.Content.ReadAsStringAsync();
        }

        public static string Get(string url, string query = null, int timeout = 10)
        {
            return GetAsync(url, query, timeout).ConfigureAwait(false).GetAwaiter().GetResult();
        }

        public static T Get<T>(string url, string query = null, int timeout = 10)
        {
            string content = Get(url, query, timeout);
            if (string.IsNullOrEmpty(content))
            {
                return default;
            }
            return JsonConvert.DeserializeObject<T>(content);
        }
        public static async Task<string> PostAsync(string url, string body, string mediaType, int timeout)
        {
            var uri = new Uri(url);
            var client = GetHttpClient(uri);
            var httpMessage = new HttpRequestMessage(HttpMethod.Post, url);
            client.Timeout = TimeSpan.FromSeconds(timeout);
            httpMessage.Content = new StringContent(body, Encoding.UTF8, mediaType);
            var resp = await client.SendAsync(httpMessage);
            if (!IsSuccess(resp.StatusCode))
            {
                return null;
            }
            return await resp.Content.ReadAsStringAsync();
        }
        public static string Post(string url, string body, string mediaType = null, int timeout = 10)
        {
            return PostAsync(url, body, mediaType ?? "application/json", timeout).ConfigureAwait(false).GetAwaiter().GetResult();
        }
        public static TResult Post<TResult, TBody>(string url, TBody body, string mediaType = null, int timeout = 10)
        {
            string json = JsonConvert.SerializeObject(body);
            string content = Post(url, json, mediaType, timeout);
            if (!string.IsNullOrEmpty(content))
            {
                return default;
            }
            return JsonConvert.DeserializeObject<TResult>(content);
        }
    }
}
